

#ifndef SSTRING_H_
#define SSTRING_H_

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>


#ifndef SUTIL_H_
#include "sutil.h"
#endif


#ifdef __cplusplus
extern "C" {
#endif

#define SSTR_INIT 	{(void*)0,(void*)0,-1,0,0}

typedef unsigned long ulong_t;
typedef long long_t;

typedef struct sstring {
	char * phead;
	char * pcurrent;
	
	long_t cursor;
	ulong_t length;
	ulong_t capacity;
} String;


char* sstrCat(struct sstring * _pDest, const char *_pSrc) {

	if(_pDest == NULL || _pSrc == NULL) {
		return (char*)NULL;
	}

	if( _pDest->length !=0 && _pDest->length >=  _pDest->capacity) {
		return (char *)0;
	}

	int srclen = strlen( _pSrc);

	if((_pDest->capacity - _pDest->length) <= srclen || _pDest->phead == NULL) {

		if(_pDest->phead == NULL) {
			_pDest->length = 0;
			_pDest->capacity = 0;
		}

		char *pNewHead = (char *)MALLOC(( _pDest->capacity + srclen) * 2 * sizeof(char));
		if(pNewHead == NULL) {
			return NULL;
		}
		if( _pDest->phead != (void*)0) {

			_pDest->phead[_pDest->length] = '\0';
			memcpy(pNewHead, _pDest->phead, _pDest->length+1);

			free( _pDest->phead);
		}

		_pDest->phead = pNewHead;
		_pDest->capacity = ( _pDest->capacity + srclen) * 2 * sizeof(char);
		_pDest->pcurrent = _pDest->phead+_pDest->length;
	}
	if(_pDest->pcurrent != NULL)
		memcpy( _pDest->pcurrent, _pSrc, srclen+1);

	_pDest->pcurrent = _pDest->pcurrent + srclen;
	_pDest->length +=srclen;

	return _pDest->phead;

}

char* sstrAdd(String *_pDest, const char c) {

	if(_pDest == NULL)
		return NULL;

	char buf[2];
	buf[0] = c;
	buf[1] = '\0';
	return sstrCat(_pDest, buf);
}

void sstrClear(struct sstring *_pStr) {
	if(_pStr == NULL)
		return;
	if(_pStr->phead != NULL)
		bzero( _pStr->phead, _pStr->capacity);
	_pStr->pcurrent = _pStr->phead;
	_pStr->length = 0;
	
	return;
}

void sstrFree(struct sstring *_pStr) {
	if(_pStr == NULL)
		return;
	free(_pStr->phead);
	_pStr->length = 0;
	_pStr->capacity = 0;
	_pStr->phead = (char *)NULL;
	_pStr->pcurrent = (char *)NULL;

	return;
}

int sstrReset(String *_pStr) {
	if( _pStr == (String *)NULL)
		return (int)-1;

	_pStr->cursor = -1;
	return (int)0;
}
#define SSTR_EOL	((char*)-1)
char* sstrGetLine(String *_pStr, char *_pBuf, ulong_t _size) {

	if( _size<=0 || _pBuf == NULL) {
		return (char *)NULL;
	}

	if( _pStr->cursor >= 0 && _pStr->phead[ _pStr->cursor] == '\0') {
		_pBuf[0] = '\0';
		return SSTR_EOL;
	}
	int n=0;
	while( _pStr->phead[++_pStr->cursor] != '\0') {
		if( _pStr->phead[ _pStr->cursor] == '\n') {
			if(n == 0) {
				continue;
			} else {
				_pBuf[n] = '\0';
				return _pBuf;
			}
		} else {
			_pBuf[n++] = _pStr->phead[ _pStr->cursor];
			if( _size == n) {
				_pBuf[_size-1] = '\0';
				return _pBuf;
			}
		}

	}
	_pBuf[n] = '\0';
	return _pBuf;
}


String* sstrClone2(String *_pDest, String* _pSrc) {
	if(_pDest == NULL || _pSrc == NULL) 
		return NULL;

	sstrClear( _pDest);	
	if(sstrCat(_pDest, _pSrc->phead) == NULL)
		return NULL;

	_pDest->length		= _pSrc->length;
	_pDest->capacity	= _pSrc->capacity;
	_pDest->cursor		= _pSrc->cursor;

	return _pDest;
}

String* sstrClone(String *_pSrc) {
	if(_pSrc == NULL)
		return NULL;

	String *_pStr = (String *)MALLOC(sizeof(String));
	_pStr ->cursor = -1;
	if(_pSrc != NULL) {
		return sstrClone2(_pStr, _pSrc);
	}
	
	return NULL;
}

#ifndef MAX_BUF_SIZE
#define MAX_BUF_SIZE	1024
#endif

int readFd(int _fd, String *_pStr) {
	if( _fd == 0 || _pStr == NULL) {
		return (int)-1;
	}
	char buf[MAX_BUF_SIZE];

	int total=0, n=0;
	while((n = read( _fd, buf, MAX_BUF_SIZE-1)) > 0) {
		buf[n] = '\0';
		sstrCat( _pStr, buf);
		total +=n;
	}
	return total;
}


int readFile(FILE *_file, String *_pStr) {
	
	if( _file == NULL || _pStr == NULL) {
		return (int)-1;
	}
	char buf[MAX_BUF_SIZE];

	int total = 0, n = 0;
	while((n = fread( buf, sizeof(char), MAX_BUF_SIZE-1, _file)) > 0) {
		buf[n] = '\0';
		sstrCat( _pStr, buf);
		total +=n;
	}
	return total;
}

#ifdef __cplusplus
}
#endif


#endif /* SSTRING_H_ */
